package drds.plus.sql_process.abstract_syntax_tree.configuration.parse;

import com.google.common.collect.Lists;
import drds.plus.common.model.Application;
import drds.plus.common.model.DataNode;
import drds.plus.common.model.DatasourceWrapper;
import drds.plus.common.model.RepositoryType;
import drds.plus.common.utils.XmlHelper;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public class ApplicationParser {
    public static Application parse(String data) {
        InputStream inputStream = new ByteArrayInputStream(data.getBytes());
        return parse(inputStream);
    }

    public static Application parse(InputStream inputStream) {
        Document document = XmlHelper.createDocument(inputStream, null);
        Element root = document.getDocumentElement();
        return parseApplication(root);
    }

    private static Application parseApplication(Element root) {
        Map<String, String> props = new HashMap<String, String>();
        NodeList childNodes = root.getChildNodes();
        Application application = new Application();

        for (int i = 0; i < childNodes.getLength(); i++) {
            Node node = childNodes.item(i);
            if ("properties".equals(node.getNodeName())) {
                props = parseProperties(node);
            } else if ("applicationId".equals(node.getNodeName())) {
                Node nameNode = node.getFirstChild();
                if (nameNode != null) {
                    application.setId(nameNode.getNodeValue());
                }
            }
        }

        NodeList dataNodeListNodeList = root.getElementsByTagName("data_node");
        List<DataNode> dataNodeList = Lists.newArrayList();
        for (int i = 0; i < dataNodeListNodeList.getLength(); i++) {
            dataNodeList.add(parseDataNode(dataNodeListNodeList.item(i), application.getId()));
        }
        application.setDataNodeList(dataNodeList);
        application.setProperties(props);
        return application;
    }

    private static DataNode parseDataNode(Node node, String applicationId) {
        Node nameNode = node.getAttributes().getNamedItem("columnName");
        Node typeNode = node.getAttributes().getNamedItem("type");
        Map<String, String> props = new HashMap<String, String>();
        List<DatasourceWrapper> datasourceWrappers = new ArrayList<DatasourceWrapper>();

        NodeList nodeList = node.getChildNodes();
        for (int i = 0; i < nodeList.getLength(); i++) {
            Node item = nodeList.item(i);
            if ("properties".equals(item.getNodeName())) {
                props = parseProperties(item);
            } else if ("datasource".equals(item.getNodeName())) {
                datasourceWrappers.add(parseDatasourceWrapper(item));
            }
        }
        DataNode dataNode = new DataNode();
        dataNode.setApplicationId(applicationId);
        if (nameNode != null) {
            dataNode.setId(nameNode.getNodeValue());
        }

        if (typeNode != null) {
            dataNode.setRepositoryType(getGroupType(typeNode.getNodeValue()));
        }

        dataNode.setProperties(props);
        dataNode.setDatasourceWrapperList(datasourceWrappers);
        return dataNode;
    }

    private static DatasourceWrapper parseDatasourceWrapper(Node node) {
        Node nameNode = node.getAttributes().getNamedItem("columnName");
        Map<String, String> props = new HashMap<String, String>();
        NodeList childNodes = node.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node item = childNodes.item(i);
            if ("properties".equals(item.getNodeName())) {
                props = parseProperties(item);
            }

        }

        DatasourceWrapper datasourceWrapper = new DatasourceWrapper();
        if (nameNode != null) {
            datasourceWrapper.setName(nameNode.getNodeValue());
        }
        datasourceWrapper.setProperties(props);
        return datasourceWrapper;
    }

    private static Map<String, String> parseProperties(Node node) {
        Map<String, String> result = new HashMap<String, String>();
        NodeList childNodes = node.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node item = childNodes.item(i);
            if ("property".equals(item.getNodeName())) {
                Node nameNode = item.getAttributes().getNamedItem("columnName");
                Node valueNode = item.getAttributes().getNamedItem("value");
                if (nameNode == null || valueNode == null) {
                    NodeList itemChildNodes = item.getChildNodes();
                    for (int j = 0; j < itemChildNodes.getLength(); j++) {
                        Node itemChild = itemChildNodes.item(j);
                        if ("columnName".equals(itemChild.getNodeName())) {
                            nameNode = itemChild.getFirstChild();
                        } else if ("value".equals(itemChild.getNodeName())) {
                            valueNode = itemChild.getFirstChild();
                        }
                    }
                }

                result.put(nameNode.getNodeValue(), valueNode.getNodeValue());
            }
        }

        return result;
    }

    private static RepositoryType getGroupType(String type) {
        if ("mysql".equalsIgnoreCase(type)) {
            return RepositoryType.mysql;
        } else if ("bdb".equalsIgnoreCase(type)) {
            return RepositoryType.bdb;
        }

        throw new UnsupportedOperationException("type:" + type);
    }
}
